package com.demo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.common.cache.CacheService;
import com.demo.common.excel.ExcelSceneConstants;
import com.demo.common.excel.ExcelService;
import com.demo.common.exceptions.ServiceException;
import com.demo.common.permission.PermissionService;
import com.demo.common.permission.login.RequestService;
import com.demo.common.permission.login.TokenInfo;
import com.demo.entity.SysUser;
import com.demo.entity.vo.SysUserSearchReq;
import com.demo.enums.SysUserStatusEnum;
import com.demo.mapper.SysUserMapper;
import com.demo.service.SysUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

import static com.demo.common.utils.CacheKeyConstants.LONGIN_LOCK;
import static com.demo.common.utils.CacheKeyConstants.LONGIN_PASSWORD_ERROR;

@Service
@ExcelService(scene = ExcelSceneConstants.USER_LIST,targetClass = SysUser.class,importMethod = "register",exportMethod = "userList")
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Resource
    private CacheService cacheService;

    @Resource
    private RequestService requestService;

    @Resource
    private PermissionService permissionService;

    @Override
    public void updateUser(SysUser sysUser){
        SysUser old = this.getById(sysUser.getId());
        if(old==null){
            throw new ServiceException("用户"+sysUser.getId()+"不存在");
        }
        Integer oldRoleId=old.getRoleId();
        SysUser updateUser=new SysUser();
        updateUser.setId(sysUser.getId());
        updateUser.setRoleId(sysUser.getRoleId());
        updateUser.setHeadImg(sysUser.getHeadImg());
        this.updateById(updateUser);
        //角色换了，清除缓存
        if(!sysUser.getRoleId().equals(oldRoleId)){
            permissionService.clearCache(Collections.singletonList(sysUser.getId()));
        }
    }

    @Override
    public String login(SysUser sysUser) {
        String mobile=sysUser.getMobile();
        SysUser user = this.getOne(new QueryWrapper<SysUser>().eq("mobile", mobile));
        if(user==null){
            throw new ServiceException("用户"+mobile+"不存在");
        }
        if(SysUserStatusEnum.FREEZE.getValue().equals(user.getStatus())){
            throw new ServiceException("用户"+mobile+"已被冻结");
        }
        String userLockKey=LONGIN_LOCK+mobile;
        boolean lock=cacheService.exist(userLockKey);
        if(lock){
            throw new ServiceException("用户多次登录失败，已被锁定,请稍后再试");
        }
        String crypt = DigestUtils.md5DigestAsHex(sysUser.getPwd().getBytes(StandardCharsets.UTF_8));
        //密码校验
        if(!user.getPwd().equals(crypt)){
            String pwdErrorKey=LONGIN_PASSWORD_ERROR+mobile;
            Integer errorCount = cacheService.getCache(pwdErrorKey);
            if(errorCount==null){
                errorCount=0;
            }
            errorCount++;
            if(errorCount>3){
                cacheService.removeCache(pwdErrorKey);
                cacheService.setCache(userLockKey,true,60*5);
            }else {
                cacheService.setCache(pwdErrorKey,errorCount,60*5);
            }
            throw new ServiceException("登录失败,密码错误");
        }
        String uuid = UUID.randomUUID().toString();
        String s = uuid + user.getMobile();
        TokenInfo tokenInfo=new TokenInfo();
        tokenInfo.setToken(DigestUtils.md5DigestAsHex(s.getBytes(StandardCharsets.UTF_8)));
        tokenInfo.setMobile(user.getMobile());
        tokenInfo.setLoginTime(LocalDateTime.now());
        tokenInfo.setUserId(user.getId());
        //token刷新时间，24*0.75=18
        tokenInfo.setFlushTime(tokenInfo.getLoginTime().plusHours(18));
        //token有效期24小时
        requestService.setTokenInfo(tokenInfo);
        return tokenInfo.getToken();
    }

    @Override
    public boolean logout() {
        requestService.removeToken();
        return true;
    }

    @Override
    public Integer register(SysUser sysUser) {
        String mobile = sysUser.getMobile();
        SysUser user = this.getOne(new QueryWrapper<SysUser>().eq(SysUser.MOBILE, mobile));
        if(user!=null){
            throw new ServiceException("手机号"+mobile+"已被注册");
        }
        SysUser insertUser=new SysUser();
        insertUser.setMobile(mobile);
        insertUser.setStatus(SysUserStatusEnum.NORMAL.getValue());
        //默认密码是手机号后六位
        insertUser.setPwd(DigestUtils.md5DigestAsHex(mobile.substring(mobile.length()-6).getBytes(StandardCharsets.UTF_8)));
        insertUser.setRoleId(sysUser.getRoleId());
        try{
            this.save(insertUser);
        }catch (DuplicateKeyException e){
            throw new ServiceException("手机号"+mobile+"已被注册");
        }
        return insertUser.getId();
    }

    @Override
    public void updatePwd(Integer userId, String oriPwd, String newPwd) {
        SysUser sysUser = this.getById(userId);
        if(sysUser==null){
            throw new ServiceException("id为"+userId+"的用户不存在");
        }
        String oldCrypt = DigestUtils.md5DigestAsHex(oriPwd.getBytes(StandardCharsets.UTF_8));
        if(!oldCrypt.equals(sysUser.getPwd())){
            throw new ServiceException("原密码不正确");
        }
        SysUser updateUser=new SysUser();
        updateUser.setId(userId);
        updateUser.setPwd(DigestUtils.md5DigestAsHex(newPwd.getBytes(StandardCharsets.UTF_8)));
        this.updateById(updateUser);
    }

    @Override
    public void resetPwd(Integer userId) {
        SysUser sysUser = this.getById(userId);
        if(sysUser==null){
            throw new ServiceException("id为"+userId+"的用户不存在");
        }
        if(SysUserStatusEnum.FREEZE.getValue().equals(sysUser.getStatus())){
            throw new ServiceException("用户"+sysUser.getMobile()+"已被冻结，请先解冻");
        }
        SysUser updateUser=new SysUser();
        String mobile=sysUser.getMobile();
        updateUser.setId(userId);
        //默认密码是手机号后六位
        updateUser.setPwd(DigestUtils.md5DigestAsHex(mobile.substring(mobile.length()-6).getBytes(StandardCharsets.UTF_8)));
        this.updateById(updateUser);
    }

    @Override
    public void freezeUser(Integer userId) {
        SysUser sysUser = this.getById(userId);
        if(sysUser==null){
            throw new ServiceException("id为"+userId+"的用户不存在");
        }
        if(SysUserStatusEnum.FREEZE.getValue().equals(sysUser.getStatus())){
            throw new ServiceException("用户"+sysUser.getMobile()+"已被冻结，无须再次冻结");
        }
        SysUser updateUser=new SysUser();
        updateUser.setId(userId);
        updateUser.setStatus(SysUserStatusEnum.FREEZE.getValue());
        this.updateById(updateUser);
    }

    @Override
    public void unfreezeUser(Integer userId) {
        SysUser sysUser = this.getById(userId);
        if(sysUser==null){
            throw new ServiceException("id为"+userId+"的用户不存在");
        }
        if(SysUserStatusEnum.NORMAL.getValue().equals(sysUser.getStatus())){
            throw new ServiceException("用户"+sysUser.getMobile()+"非冻结状态，无须冻结");
        }
        SysUser updateUser=new SysUser();
        updateUser.setId(userId);
        updateUser.setStatus(SysUserStatusEnum.NORMAL.getValue());
        this.updateById(updateUser);
    }

    @Override
    public Page<SysUser> userList(SysUserSearchReq request) {
        Page<SysUser> page=new Page<>(request.getCurrent(),request.getSize());
        QueryWrapper<SysUser> queryWrapper=new QueryWrapper<>();
        //构建查询参数
        queryWrapper.in(!CollectionUtils.isEmpty(request.getRoleIds()),SysUser.ROLE_ID,request.getRoleIds());
        queryWrapper.eq(request.getId()!=null,SysUser.ID,request.getId());
        queryWrapper.eq(request.getStatus()!=null,SysUser.STATUS,request.getStatus());
        queryWrapper.like(StringUtils.isNotBlank(request.getMobile()),SysUser.MOBILE,request.getMobile());
        if(request.getStartTime()!=null&&request.getEndTime()!=null){
            queryWrapper.between(SysUser.CREATE_TIME,request.getStartTime(),request.getEndTime());
        }
        this.page(page,queryWrapper);
        return page;
    }

    @Override
    public List<SysUser> getUserByRole(Integer roleId) {
        return this.list(new QueryWrapper<SysUser>().eq(SysUser.ROLE_ID,roleId));
    }
}